﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BadHabit.Factory.Controls {

    /// <summary>
    /// Interaction logic for BacklogDataGrid.xaml
    /// </summary>
    public partial class BacklogDataGrid : UserControl {

        // this is a key for the BacklogItemFilter property
        internal static readonly DependencyProperty BacklogFilterProperty =
            DependencyProperty.Register("BacklogFilter", typeof(BacklogFilter), typeof(BacklogDataGrid), new PropertyMetadata(BacklogFilter.PLANNED_BACKLOG, new PropertyChangedCallback(OnBacklogFilterChanged)));

        public BacklogFilter BacklogFilter {
            get {
                return (BacklogFilter)GetValue(BacklogFilterProperty);
            }
            set {
                SetValue(BacklogFilterProperty, value);
            }
        }

        internal static readonly DependencyProperty AutoPlanProperty =
            DependencyProperty.Register("AutoPlan", typeof(bool), typeof(BacklogDataGrid), null);

        public bool AutoPlan {
            get {
                return (bool)GetValue(AutoPlanProperty);
            }
            set {
                SetValue(AutoPlanProperty, value);
            }
        }


        /// <summary>
        /// If any filter has changed, applies it.
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void OnBacklogFilterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
            BacklogDataGrid backlogDataGrid = d as BacklogDataGrid;
            backlogDataGrid.UpdateDataGridViewCollection();
        }
        
            
        
        /// <summary>
        /// Default constructor.
        /// </summary>
        public BacklogDataGrid() {
            InitializeComponent();

            // CAN NOT ADD MOUSEDOWN EVENT VIA XAML
            // CANNOT ADD USING += OPERATOR
            // NEED TO DO THIS WAY
            backlogDataGrid.AddHandler(FrameworkElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(ReorderableListBox_MouseLeftButtonDown), true);
        
        }


        List<Expander> expanderList = new List<Expander>();

        /// <summary>
        /// WPF BUG. You can not set expander equal to false at XAML when using grouping.
        /// So do it manualy here.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Expander_Loaded(object sender, RoutedEventArgs e) {            
            Expander c = sender as Expander;
            if (c == null)
                return;
            System.Data.DataRowView sprint = c.DataContext as System.Data.DataRowView;
            // ADDED THIS LINE IN ORDER TO STOP A CRASH AT THE EXPANDER_LOADED
            // NO SURE IF IT SOLVE THE PROBLEM
            if (sprint == null)
                return;
            if (DBNull.Value.Equals(sprint["IsCurrentSprint"]))
                return;
            if(!(bool)sprint["IsCurrentSprint"])
                c.IsExpanded = false;
            
        }

        /// <summary>
        /// Gets the datacontext as a project dataset.
        /// </summary>
        private Data.ProjectDataSet DataContextAsProjectDataSet {
            get {
                return DataContext as Data.ProjectDataSet;
            }
        }

        private bool columnsCreated = false;

        /// <summary>
        /// Creates the unit columns at the datagid
        /// </summary>
        private void CreateUnitCollumns() {
         
            // first remove any unit columns from any previous bind
            for (int i = backlogDataGrid.Columns.Count - 1; i > 0; i--) {
                String columnName = backlogDataGrid.Columns[i].GetValue(FrameworkElement.NameProperty).ToString();
                if (columnName.StartsWith("unit"))
                    backlogDataGrid.Columns.RemoveAt(i);
            }

            foreach (Data.ProjectDataSet.BacklogItemUnitRow unit in 
                DataContextAsProjectDataSet.BacklogItemUnit.Select("Type=" + (short)TeamRoles.TEAM +
                " OR Type=" + (short)TeamRoles.SCRUM_MASTER +
                " OR Type=" + (short)TeamRoles.QUALITY_ASSURANCE)) {

                

                String columnName = DataContextAsProjectDataSet.GetVisibleUnitColumnName(unit.UnitName);
                

                Microsoft.Windows.Controls.DataGridTextColumn c = new Microsoft.Windows.Controls.DataGridTextColumn();
                c.CanUserResize = true;
                c.Header = unit.UnitName;
                c.SetValue(FrameworkElement.NameProperty, columnName);
                c.CellStyle = (Style) backlogDataGrid.Resources["BacklogRightAlignCellStyle"];
                c.EditingElementStyle = (Style) Application.Current.Resources["TransparentEditingElementStyle"];
                
                Binding b = new Binding(columnName);
                b.StringFormat = "F1";
                c.Binding = b;
                backlogDataGrid.Columns.Add(c);
            }

            columnsCreated = true;

        }


     

      


       

        /// <summary>
        /// Verifies the key pressed and take the proper actions.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backlogDataGrid_PreviewKeyDown(object sender, KeyEventArgs e) {

            if (e.Key == Key.Insert) {                
                AddNewBacklogItem();
                e.Handled = true;                
            }


            if (e.Key == Key.Enter) {                
                if(backlogDataGrid.SelectedIndex==backlogDataGrid.Items.Count-1)
                    AddNewBacklogItem();                
            }
                                               
                                               
        }

      

        /// <summary>
        /// Gets the BacklogDataGrid DataContext as a BindingListCollectionView.
        /// </summary>
        public BindingListCollectionView VisibleBacklogItemView {
            get {                
                return (BindingListCollectionView)CollectionViewSource.GetDefaultView(backlogDataGrid.ItemsSource);
            }            
        }

        /// <summary>
        /// Deletes a backlog item.
        /// </summary>
        private void DeleteVisibleBacklogItem() {

            // finds the previuos row to insert after
            if (backlogDataGrid.SelectedItem == null)
                return;
            System.Data.DataRowView selectedItem = backlogDataGrid.SelectedItem as System.Data.DataRowView;

            // if the item is at any proposal, you can not remove
            System.Data.DataRow[] atProposal = DataContextAsProjectDataSet.ProposalItem.Select("BacklogItemUId='" + selectedItem["BacklogItemUId"] + "'");
            if (atProposal != null && atProposal.Length > 0) {
                Windows.Error.ShowAlert(Properties.Resources.You_can_not_delete_this_item);
                return;
            }
                        

            // verifies if the item can be removed
            Data.ProjectDataSet.SprintRow removeSprintAlso;
            bool canRemove = ShouldRemoveVisibleBacklogItem(selectedItem, out removeSprintAlso);
            if (!canRemove)
                return;

            // remove item
            VisibleBacklogItemView.Remove(backlogDataGrid.SelectedItem);
            
            // remove sprint
            if (removeSprintAlso != null)
                removeSprintAlso.Delete();

            
        }

        /// <summary>
        /// Verifies if a visible backlog item can be removed.
        /// If is the last item, of the last sprint, also ask for remove the sprint.
        /// </summary>
        /// <param name="itemView">The item to be removed view</param>
        /// <param name="removeSprintAlso">A sprint Row, will have null if no sprint should be removed</param>
        /// <returns>True if the item can be removed</returns>
        private bool ShouldRemoveVisibleBacklogItem(System.Data.DataRowView itemView, out Data.ProjectDataSet.SprintRow removeSprintAlso) {

            removeSprintAlso = null;

            if (!CanRemoveVisibleBacklogItem(itemView))
                return false;

            string sprintUId = itemView["sprintUId"].ToString();
            Data.ProjectDataSet.SprintRow sprint = DataContextAsProjectDataSet.Sprint.FindBySprintUId(sprintUId);
            System.Data.DataRow[] sprintItems = DataContextAsProjectDataSet.VisibleBacklogItem.Select("SprintUId='" + sprintUId + "'");

            // if is the last item, but is the last sprint, and you got more than one sprint....remove the sprint
            if (sprintItems.Length == 1 && sprint.IsLastSprint && sprint.SprintNumber > 1) {
                MessageBoxResult d = Windows.Error.ShowDialog(
                    Properties.Resources.Remove_item_and_sprint, Properties.Resources.Remove_Last_Sprint, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
                if (d == MessageBoxResult.Yes) {
                    removeSprintAlso = sprint;
                    return true;
                }
                return false;
            }

            return true;
        }

        /// <summary>
        /// Verifies if a visible backlog item can be removed.
        /// If is the last item, of the last sprint, also ask for remove the sprint.
        /// </summary>
        /// <param name="itemView">The item to be removed view</param>
        /// <param name="removeSprintAlso">A sprint Row, will have null if no sprint should be removed</param>
        /// <returns>True if the item can be removed</returns>
        private bool CanRemoveVisibleBacklogItem(System.Data.DataRowView itemView) {

            if (!Client.UserIsInRole(TeamRoles.SCRUM_MASTER))
                return false;

            // if is a hour bank project, you can not delete row
            if (DataContextAsProjectDataSet.Project[0].HourBankMode > 0
                && DataContextAsProjectDataSet.Project[0].HourBankMode!=4) // differ from 3 is my friend Valle excepetion project
                return false;

            // if the sprint is already planned get out of my way
            if ((bool)itemView["IsPlanOver"])
                return false;

            string sprintUId = itemView["sprintUId"].ToString();
            Data.ProjectDataSet.SprintRow sprint = DataContextAsProjectDataSet.Sprint.FindBySprintUId(sprintUId);
            System.Data.DataRow[] sprintItems = DataContextAsProjectDataSet.VisibleBacklogItem.Select("SprintUId='" + sprintUId + "'");
          
            // if is the last item of the first sprint you can not remove
            if (sprintItems.Length == 1 && sprint.SprintNumber == 1) 
                return false;            

            return true;
        }
        
        /// <summary>
        /// Adds a brand new backlogitem into the grid.
        /// </summary>
        public void AddNewBacklogItem() {

            backlogDataGrid.CommitEdit();

            System.Data.DataRowView selectedItem = null;

            // if is a hour bank project, you can not insert row
            /*
            if (DataContextAsProjectDataSet.Project[0].HourBankMode > 0)
                return;
            */

            // finds the previuos row to insert after
            if (backlogDataGrid.CurrentCell == null)
                selectedItem = backlogDataGrid.Items[backlogDataGrid.Items.Count-1] as System.Data.DataRowView;
            else
                selectedItem = backlogDataGrid.CurrentCell.Item as System.Data.DataRowView;

            if (selectedItem == null)
                return;

            int selectIndex = backlogDataGrid.Items.IndexOf(selectedItem);

            System.Data.DataRowView nextItem = null;
            if (selectIndex < backlogDataGrid.Items.Count - 1)
                nextItem = backlogDataGrid.Items[selectIndex + 1] as System.Data.DataRowView;

            System.Data.DataRowView previousItem = selectedItem;
            if (selectIndex > 0)
                previousItem = backlogDataGrid.Items[selectIndex - 1] as System.Data.DataRowView;
            

            // if the sprint is already planned get out of my way
            if ((bool)selectedItem["IsPlanOver"])
                return;

            // gets the project dataset                      
            Data.ProjectDataSet dsProject = DataContextAsProjectDataSet;
            Data.ProjectDataSet.ProjectRow project = dsProject.Project.FindByProjectUId(selectedItem["ProjectUId"].ToString());


            MakeRoom(selectIndex);

            // creates the new backlogitem row
            Data.ProjectDataSet.BacklogItemRow item = dsProject.BacklogItem.NewBacklogItemRow();
            item.BacklogItemUId = Guid.NewGuid().ToString().ToLower();
            item.BacklogItemNumber = project.NextBacklogItemNumber;
            item.ProjectRow = project;
            item.ProjectUId = project.ProjectUId;
            item.Title = "";
            item.Description = "";
            item.Status = (int)BacklogItemStatus.REQUIRED;
            item.GroupName = previousItem["GroupName"].ToString();
            item.Size = 0;
            item.BusinessValue = GetNewItemBusinessValue(selectedItem, nextItem);
            item.CreateDate = DateTime.Now;
            item.HourBankMonth = (short) 0;
            item.HourBankYear = 0;
            item.IsBugCorrection = false;

            // adds it to the dataset
            dsProject.BacklogItem.AddBacklogItemRow(item);
            item.InsertZeroHourValues(selectedItem["SprintUId"].ToString());

            System.Data.DataRowView o = (System.Data.DataRowView)VisibleBacklogItemView.AddNew();
            System.Data.DataRow visibleRow = dsProject.BacklogItem.AsVisibleBacklogItem(item, selectedItem["SprintUId"].ToString(), project.Baseline);
            o.Row.ItemArray = visibleRow.ItemArray;
            VisibleBacklogItemView.CommitNew();

            backlogDataGrid.UpdateLayout();

            // sets the select item position
            backlogDataGrid.SelectedItem = o;
            SetFocusOnTheCell(2);
                     
        }

        /// <summary>
        /// Set the focu on the Item Cell of the current selected row.
        /// </summary>
        /// <remarks>This only works if the current cell is the first one.</remarks>
        private void SetFocusOnTheCell(int cellIdx) {

            if (backlogDataGrid.SelectedItem == null)
                return;

            Microsoft.Windows.Controls.DataGridCell cell = Helper.GetCell(backlogDataGrid, backlogDataGrid.SelectedIndex, cellIdx);
            if (cell == null)
                return;
                                    
            Expander expander = Helper.FindVisualParent<Expander>(cell);
            if (expander != null)
                expander.IsExpanded = true;

            cell.Focus();
            System.Windows.Input.Keyboard.Focus(cell);
            
                        
        }


        /// <summary>
        /// Gets the business value for a item inserted bettewn two items.
        /// </summary>
        /// <param name="item">The first item</param>
        /// <param name="nextItem">The second item</param>
        /// <returns>The business value</returns>
        private int GetNewItemBusinessValue(System.Data.DataRowView item, System.Data.DataRowView nextItem) {
            int itemValue = 1000;
            int nextItemValue = 0;
            if (item["BusinessValue"] != DBNull.Value)
                itemValue = (int) item["BusinessValue"];

            // no next item....so just decrease 10
            if (nextItem == null)
                return itemValue - 10;

            if (nextItem["BusinessValue"] != DBNull.Value)
                nextItemValue = (int)nextItem["BusinessValue"];

            return nextItemValue + (itemValue - nextItemValue) / 2;


        }


        /// <summary>
        /// Update the view binded to the datagrid.
        /// IMPORTANTE REMARKS:
        /// (1) it does not work creating de CollectionView at the XAML. The GroupDescriptions get lost after bind.
        /// (2) it should be called after th Loaded event, otherwise the columns width get screwed up.
        /// </summary>
        public void UpdateDataGridViewCollection() {

            

            if (DataContextAsProjectDataSet == null)
                return;

            if(!columnsCreated)
                CreateUnitCollumns();

            
        
            
            backlogDataGrid.ItemsSource = DataContextAsProjectDataSet.VisibleBacklogItem.DefaultView;
            BindingListCollectionView view = (BindingListCollectionView)CollectionViewSource.GetDefaultView(backlogDataGrid.ItemsSource);

            if (BacklogFilter.FULL_BACKLOG.Equals(this.BacklogFilter))
                view.CustomFilter = "IsVisible=1";

            if (BacklogFilter.PLANNED_BACKLOG.Equals(this.BacklogFilter))
                view.CustomFilter = "IsVisible=1 and SprintNumber >=" + DataContextAsProjectDataSet.Project[0].Baseline;

            if (BacklogFilter.SELECTED_BACKLOG.Equals(this.BacklogFilter)) {
                if (DataContextAsProjectDataSet.Project[0].CurrentSprint != null)
                    view.CustomFilter = "IsVisible=1 and SprintNumber=" + DataContextAsProjectDataSet.Project[0].CurrentSprint.SprintNumber;
                else
                    view.CustomFilter = "IsVisible=1";
            }

            
            
            view.GroupDescriptions.Clear();
            view.GroupDescriptions.Add(new PropertyGroupDescription("SprintUId"));

            view.SortDescriptions.Clear();
            view.SortDescriptions.Add(new System.ComponentModel.SortDescription("SprintNumber", System.ComponentModel.ListSortDirection.Ascending));
            view.SortDescriptions.Add(new System.ComponentModel.SortDescription("BusinessValue", System.ComponentModel.ListSortDirection.Descending));
            view.SortDescriptions.Add(new System.ComponentModel.SortDescription("Status", System.ComponentModel.ListSortDirection.Ascending));
            view.SortDescriptions.Add(new System.ComponentModel.SortDescription("BacklogItemNumber", System.ComponentModel.ListSortDirection.Ascending));


            


        }
                
        /// <summary>
        /// Attach a ColumnChanging event to detect sprint date change and shift sprints.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UserControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) {
            columnsCreated = false;
            DataContextAsProjectDataSet.Sprint.ColumnChanging += new System.Data.DataColumnChangeEventHandler(Sprint_ColumnChanging);
           
        }

        

                
        /// <summary>
        /// If the sprint date change, shifts the ahead sprints.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Sprint_ColumnChanging(object sender, System.Data.DataColumnChangeEventArgs e) {
            // if the sprint expiration date was changed
            if (e.Column == DataContextAsProjectDataSet.Sprint.ExpirationDateColumn) {
                Data.ProjectDataSet.SprintRow sprint = e.Row as Data.ProjectDataSet.SprintRow;                
                Client.ShiftSprints(sprint, (DateTime)e.ProposedValue);                                
            }
        }

        /// <summary>
        /// Verify if the user can close the project.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DeleteBacklogItem_CanExecute(object sender, CanExecuteRoutedEventArgs e) {            

            // can not delete if no row is selected
            if (backlogDataGrid.SelectedItem == null) {
                e.CanExecute = false;
                return;
            }
            
            // can not delete planned rows
            System.Data.DataRowView selectedItem = backlogDataGrid.SelectedItem as System.Data.DataRowView;
            
            e.CanExecute = CanRemoveVisibleBacklogItem(selectedItem);

            
        }

        
        private void DeleteBacklogItem_Executed(object sender, ExecutedRoutedEventArgs e) {
            DeleteVisibleBacklogItem();
        }

        private void SizeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
       
            if (AutoPlan)
                CalcAutoPlan();            
        }


        private void CalcAutoPlan() {

            System.Data.DataRowView item = VisibleBacklogItemView.CurrentItem as System.Data.DataRowView;
            if (item == null)
                return;

            //no size type, get out
            if (item["SizeItemType"] == null || item["SizeItemType"] == DBNull.Value)
                return;

            short sizeItemType = (short) item["SizeItemType"];            
            
            VisibleBacklogItemView.EditItem(item);

            foreach (Data.ProjectDataSet.BacklogItemUnitRow unit in DataContextAsProjectDataSet.BacklogItemUnit.Select("Type <> " + (short) BadHabit.Factory.TeamRoles.CLIENT_CONTACT )) {
                string unitNameColumn = DataContextAsProjectDataSet.GetVisibleUnitColumnName(unit.UnitName);
                
                Data.TaskDataSet.AverageHoursBySizeItemTypeRow average = Client.AverageHoursBySizeItemType.FindBySizeItemTypeUnitName(sizeItemType, unit.UnitName);
                if (average != null)
                    item[unitNameColumn] = Math.Round(average.Hours, 1);
                else
                    item[unitNameColumn] = 0;
            }
            
            VisibleBacklogItemView.CommitEdit();
            
        }


        
        private void backlogDataGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e) {

            UIElement source = e.OriginalSource as UIElement;
            if (source == null)
                return;
            var row = Helper.FindVisualParent<Microsoft.Windows.Controls.DataGridRow>(source);
            if (row == null) return;

            Windows.BacklogItemDetail w = new BadHabit.Factory.Windows.BacklogItemDetail(DataContextAsProjectDataSet.Project[0], VisibleBacklogItemView);
            w.ShowDialog();
            e.Handled = true;
        }

        private void detailsMenuItem_Click(object sender, RoutedEventArgs e) {
            Windows.BacklogItemDetail w = new BadHabit.Factory.Windows.BacklogItemDetail(DataContextAsProjectDataSet.Project[0], VisibleBacklogItemView);
            w.ShowDialog();
            e.Handled = true;
        }

        private void MoveUpClick_Executed(object sender, ExecutedRoutedEventArgs e) {
            System.Data.DataRowView currentItem = VisibleBacklogItemView.CurrentItem as System.Data.DataRowView;

            if (!CanMoveItemUp(currentItem))
                return;

            System.Data.DataRowView previousItem = null;
            if(VisibleBacklogItemView.CurrentPosition>=2)
                previousItem = VisibleBacklogItemView.GetItemAt(VisibleBacklogItemView.CurrentPosition - 2) as System.Data.DataRowView;

            InsertItemAfter(currentItem, previousItem);

            backlogDataGrid.ScrollIntoView(currentItem);
            backlogDataGrid.UpdateLayout();
            VisibleBacklogItemView.MoveCurrentTo(currentItem);

            SetFocusOnTheCell(3);

        }

        private void MoveDownClick_Executed(object sender, ExecutedRoutedEventArgs e) {
            System.Data.DataRowView currentItem = VisibleBacklogItemView.CurrentItem as System.Data.DataRowView;
            if (!CanMoveItemDown(currentItem))
                return;
            

            System.Data.DataRowView nextItem = VisibleBacklogItemView.GetItemAt(VisibleBacklogItemView.CurrentPosition + 1) as System.Data.DataRowView;
            
            InsertItemAfter(currentItem, nextItem);

            backlogDataGrid.ScrollIntoView(currentItem);
            backlogDataGrid.UpdateLayout();
            VisibleBacklogItemView.MoveCurrentTo(currentItem);


            SetFocusOnTheCell(3);
        }

        private bool CanMoveItemUp(System.Data.DataRowView currentItem) {
            if (currentItem == null)
                return false;

            if (!Client.UserIsInRole(TeamRoles.SCRUM_MASTER) && !Client.UserIsInRole(TeamRoles.PRODUCT_OWNER))
                return false;


            if (backlogDataGrid.SelectedItems.Count > 1)
                return false;
            int currentPos = VisibleBacklogItemView.IndexOf(currentItem);
            if (currentPos <= 0)
                return false;

            System.Data.DataRowView previousItem = VisibleBacklogItemView.GetItemAt(currentPos - 1) as System.Data.DataRowView;
            if (previousItem == null)
                return false;


            if ((bool)previousItem["IsPlanOver"])
                return false;

            return true;
        }


        private bool CanMoveItemDown(System.Data.DataRowView currentItem) {            
            if (currentItem == null)
                return false;

            if (!Client.UserIsInRole(TeamRoles.SCRUM_MASTER) && !Client.UserIsInRole(TeamRoles.PRODUCT_OWNER))
                return false;

            if (backlogDataGrid.SelectedItems.Count > 1)
                return false;
            int currentPos = VisibleBacklogItemView.IndexOf(currentItem);
            if (currentPos == VisibleBacklogItemView.Count - 1)
                return false;
            return true;
        }

 

        private void MoveUpClick_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
            e.CanExecute = CanMoveItemUp(VisibleBacklogItemView.CurrentItem as System.Data.DataRowView);
        }

        private void MoveDownClick_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
            e.CanExecute = CanMoveItemDown(VisibleBacklogItemView.CurrentItem as System.Data.DataRowView);
        }
        /// <summary>
        /// Replan the item to another sprint.
        /// basically it copies the item hour values to another sprint.
        /// </summary>
        /// <param name="item">The item to be replaned</param>
        /// <param name="sprintUId">The new sprintUId</param>
        private void RePlanBacklogItem(System.Data.DataRowView item, string sprintUId) {
            // no item, no replan
            Data.ProjectDataSet.BacklogItemRow backlogItem = item.Row as Data.ProjectDataSet.BacklogItemRow;
            if (backlogItem == null)
                return;

            // if it was replanned before, get out
            if (backlogItem.HasVisibleItemAtSprint(sprintUId)) {
                Windows.Error.ShowAlert(Properties.Resources.Can_not_replan_item);
                return;
            }

            // replan it
            System.Data.DataRowView o = (System.Data.DataRowView)VisibleBacklogItemView.AddNew();
            backlogItem.ReplanToSprint(sprintUId, o);
            VisibleBacklogItemView.CommitNew();

            backlogItem.InsertZeroHourValues(sprintUId);

            // set it to the current item            
            backlogDataGrid.SelectedItem = o;
            SetFocusOnTheCell(2);

        }

        private void OpenItemDetail_Executed(object sender, ExecutedRoutedEventArgs e) {
            Windows.BacklogItemDetail w = new BadHabit.Factory.Windows.BacklogItemDetail(DataContextAsProjectDataSet.Project[0], VisibleBacklogItemView);
            w.Show();
        }

        private void BreakSprint_Executed(object sender, ExecutedRoutedEventArgs e) {
            Windows.SprintBreak w = new BadHabit.Factory.Windows.SprintBreak(DataContextAsProjectDataSet);
            w.ShowDialog();
            UpdateDataGridViewCollection();
        }



        #region DragDrop

        //containers
        private Microsoft.Windows.Controls.DataGridRow _sourceContainer;
        private Microsoft.Windows.Controls.DataGridRow _targetContainer;
        //adorners
        
        private Adoners.BacklogItemInsertionAdorner _insertionAdorner;

        private Point _startingMousePosition;
        private object _draggedItem;
   
        

        
        List<object> beforeMouseDownSelectedItems = null;
        void ReorderableListBox_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) {

            _startingMousePosition = e.GetPosition(backlogDataGrid);

            
            Visual visual = e.OriginalSource as Visual;
            _sourceContainer = (Microsoft.Windows.Controls.DataGridRow) Helper.GetItemContainer(backlogDataGrid, visual);

            // HOLLY CRAP
            // need to do this cuz when you drag and drop multiple items
            // the datagrid unselected the itens
            beforeMouseDownSelectedItems = null;
            if (_sourceContainer != null) {
                this._draggedItem = _sourceContainer.DataContext;

                if (_sourceContainer.IsSelected) {                    
                    beforeMouseDownSelectedItems = new List<object>();
                    foreach (object o in backlogDataGrid.SelectedItems) 
                        beforeMouseDownSelectedItems.Add(o);                        
                    
                }

            }                               
        }

        // HOLLY CRAP
        // need to do this cuz when you drag and drop multiple items
        // the datagrid unselected the itens
        private void ReorderableListBox_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
         
            if (beforeMouseDownSelectedItems!=null) {
                foreach (object o in beforeMouseDownSelectedItems) 
                    backlogDataGrid.SelectedItems.Add(o);
                beforeMouseDownSelectedItems = null;
            }
        }

        void ReorderableListBox_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) {
            this._draggedItem = null;      
        }

        void ReorderableListBox_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e) {

            if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed && this._draggedItem != null && !backlogDataGrid.IsReadOnly) {


                Point position = e.GetPosition(backlogDataGrid);
                
                if (Helper.IsMovementBigEnough(_startingMousePosition, position)) {

                    // DO NOT REMOVE THIS LINE
                    // IF THERE IS A CELL ON EDIT MODE AND WE TRY TO DRAG
                    // AFTER THE ITEM IS REORDERED THE KEYBOARD NAVIGATION GET LOST
                    // SO: COMMITEDIT FIRST, AND THEN DRAG
                    if (VisibleBacklogItemView.IsEditingItem) {
                        backlogDataGrid.CommitEdit();
                        return;
                    }

                    if (backlogDataGrid.SelectedItems.Count == 0)
                        return;
                        
                    DragDrop.DoDragDrop(backlogDataGrid, _draggedItem, DragDropEffects.Move);

                    if (_targetContainer == null)
                        return;
                    
                    System.Data.DataRowView targetItem = (System.Data.DataRowView)_targetContainer.DataContext;
                    List<System.Data.DataRowView> itemsToMove = new List<System.Data.DataRowView>();
                    foreach (System.Data.DataRowView item in backlogDataGrid.SelectedItems)
                        itemsToMove.Add(item);

                    for(int i=0; i<itemsToMove.Count; i++) {
                        InsertItemAfter((System.Data.DataRowView)itemsToMove[i], targetItem);
                        targetItem = (System.Data.DataRowView)itemsToMove[i];
                    }

                    backlogDataGrid.ScrollIntoView((System.Data.DataRowView)_sourceContainer.DataContext);
                    backlogDataGrid.UpdateLayout();

                    backlogDataGrid.SelectedItems.Clear();
                    for (int i = 0; i < itemsToMove.Count; i++) 
                        backlogDataGrid.SelectedItems.Add(itemsToMove[i]);
                    


                }

            }
        }

        

        void ReorderableListBox_PreviewDragEnter(object sender, DragEventArgs e) {
            DecideDropTarget(e);

            if (this._draggedItem != null)
                CreateInsertionAdorner();
            
            e.Handled = true;
        }

        void ReorderableListBox_PreviewDragOver(object sender, DragEventArgs e) {
            DecideDropTarget(e);

            if (this._draggedItem != null)
                UpdateInsertionAdornerPosition();
            
            e.Handled = true;
        }

        void ReorderableListBox_PreviewDragLeave(object sender, DragEventArgs e) {            
            if (this._draggedItem != null)
                RemoveInsertionAdorner();            
            e.Handled = true;
        }

        void ReorderableListBox_PreviewDrop(object sender, DragEventArgs e) {            
            if (this._draggedItem != null)
                RemoveInsertionAdorner();            
        }


        private void CreateInsertionAdorner() {
            if (_targetContainer != null) {
                var adornerLayer = AdornerLayer.GetAdornerLayer(this._targetContainer);
                this._insertionAdorner = new Adoners.BacklogItemInsertionAdorner(this._targetContainer, adornerLayer);
            }
        }

        private void UpdateInsertionAdornerPosition() {
            if (this._insertionAdorner != null)      
                this._insertionAdorner.InvalidateVisual();
            
        }

        private void RemoveInsertionAdorner() {
            if (this._insertionAdorner != null) {
                this._insertionAdorner.Detach();
                this._insertionAdorner = null;
            }
        }

        // If the types of the dragged data and ItemsControl's source are compatible, 
        // there are 3 situations to have into account when deciding the drop target:
        // 1. mouse is over an items container
        // 2. mouse is over the empty part of an ItemsControl, but ItemsControl is not empty
        // 3. mouse is over an empty ItemsControl.
        // The goal of this method is to decide on the values of the following properties: 
        // targetItemContainer, insertionIndex and isInFirstHalf.
        private void DecideDropTarget(DragEventArgs e) {            
            FrameworkElement newTarget = Helper.GetItemContainer(backlogDataGrid, e.OriginalSource as Visual);
            if (newTarget == null)
                return;

            this._targetContainer = (Microsoft.Windows.Controls.DataGridRow) Helper.GetItemContainer(backlogDataGrid, e.OriginalSource as Visual);
            Point positionRelativeToItemContainer = e.GetPosition(this._targetContainer);
            
        }


        private void InsertItemAfter(System.Data.DataRowView item, System.Data.DataRowView targetItem) {
            
            // if target and item is the same get out
            if (item == targetItem)
                return;
            
            // if the item was alredy planned before, call the REPLAN method instead of move
            if ((bool)item["IsPlanOver"]) {
                MessageBoxResult d = Windows.Error.ShowDialog(
                    Properties.Resources.This_item_has_already_been_planned, Properties.Resources.Item_Re_Plan, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
                if (d == MessageBoxResult.No)
                    return;

                RePlanBacklogItem(item, (string)targetItem["SprintUId"]);
            }

            // if the target is a alreday planned sprint, get out
            if (targetItem != null && (bool)targetItem["IsPlanOver"])
                return;

            // if should move before the first
            bool movingBeforeFirst = false;
            if (targetItem == null) {
                movingBeforeFirst = true;
                targetItem = VisibleBacklogItemView.GetItemAt(0) as System.Data.DataRowView;
                if (targetItem == null)
                    return;
            }
            
            if (targetItem["BusinessValue"] == null || targetItem["BusinessValue"] == DBNull.Value)
                return;
                                                
            // move implies in remove from one place and put in another
            // so check if the item can be removed           
            Data.ProjectDataSet.SprintRow removeSprintAlso;
            bool canRemoveItem = ShouldRemoveVisibleBacklogItem(item, out removeSprintAlso);
            if (!canRemoveItem)
                return;

            
            // finds out the next item after target
            int targetIdx = VisibleBacklogItemView.IndexOf(targetItem);            
            
            //  make room for insertion
            if (!movingBeforeFirst)
                MakeRoom(targetIdx);

            // if not the last item, gets the afterTargetBusinessValue
            int targetBV = (int)targetItem["BusinessValue"];
            int afterTargetBV = targetBV - 20;
            if (targetIdx < VisibleBacklogItemView.Count - 1) {
                System.Data.DataRowView afterTargetItem = VisibleBacklogItemView.GetItemAt(targetIdx + 1) as System.Data.DataRowView;
                afterTargetBV = (int)afterTargetItem["BusinessValue"];
            }

            int itemBV;            
            if(movingBeforeFirst)
                itemBV = targetBV + 10;
            else
                itemBV = (afterTargetBV + targetBV) / 2;

            
            // this is fucking cool...thanks .net 3.5 SP1       
            VisibleBacklogItemView.EditItem(item);
            if (targetItem["SprintUId"] != item["SprintUId"])
                item["SprintUId"] = targetItem["SprintUId"];
            item["BusinessValue"] = itemBV;            
            VisibleBacklogItemView.CommitEdit();

            
            // remove sprint            
            if (removeSprintAlso != null)
                DataContextAsProjectDataSet.Sprint.RemoveSprintRow(removeSprintAlso);
            
        }

        private void MakeRoom(int idx) {

            // if is the last item, always have room
            if (idx >= VisibleBacklogItemView.Count - 1) 
                return;
            
            int afterIdx = idx + 1;

            System.Data.DataRowView item = VisibleBacklogItemView.GetItemAt(idx) as System.Data.DataRowView;                       
            System.Data.DataRowView afterItem = VisibleBacklogItemView.GetItemAt(afterIdx) as System.Data.DataRowView;

            // if the after item got less businessvalue, it have room
            if ((int)afterItem["BusinessValue"] + 10 < (int)item["BusinessValue"]) 
                return;

            VisibleBacklogItemView.EditItem(afterItem);
            afterItem["BusinessValue"] = (int)item["BusinessValue"] - 10;
            
            MakeRoom(afterIdx);


        }

  

        #endregion DragDrop

            


        //private bool IsEditing { get; set; }
        //private void backlogDataGrid_BeginningEdit(object sender, Microsoft.Windows.Controls.DataGridBeginningEditEventArgs e) {
        //    IsEditing = true;
        //}

        //private void backlogDataGrid_CellEditEnding(object sender, Microsoft.Windows.Controls.DataGridCellEditEndingEventArgs e) {
        //    IsEditing = false;
        //}

             

        
    }
}
